package com.yupi.yuapiinterface.aop;



import com.yupi.yuapiclientsdk.utils.SignUtils;
import com.yupi.yuapiinterface.annotation.ApiAuthCheck;
import com.yupi.yuapiinterface.constant.bizz.ErrorCode;
import com.yupi.yuapiinterface.exception.BusinessException;
import com.yupi.yuapiinterface.model.User;
import com.yupi.yuapiinterface.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * API签名认证切面
 */
@Aspect
@Component
@Slf4j
@Order(1) // 数值比 InvokeCountAspect 小，优先级更高
public class ApiAuthAspect {
    
    @Autowired
    private UserService userService;
    
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    
    /**
     * 环绕通知，处理API签名认证
     */
    @Around("@annotation(apiAuthCheck)")
    public Object doApiAuth(ProceedingJoinPoint joinPoint, ApiAuthCheck apiAuthCheck) throws Throwable {
        // 如果不需要认证，直接执行
        if (!apiAuthCheck.requireAuth()) {
            return joinPoint.proceed();
        }
        
        HttpServletRequest request = getRequest();
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "无法获取请求信息");
        }
        try {
            // 1. 获取请求头参数
            String accessKey = request.getHeader("accessKey");
            String nonce = request.getHeader("nonce");
            String timestamp = request.getHeader("timestamp");
            String sign = request.getHeader("sign");
            String body = request.getHeader("body");
            // 2. 参数校验
            if (StringUtils.isAnyBlank(accessKey, nonce, timestamp, sign, body)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不完整");
            }
            // 3. 时间戳校验（5分钟内有效）
            long currentTime = System.currentTimeMillis() / 1000;
            long requestTime = Long.parseLong(timestamp);
            if (currentTime - requestTime > 300) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求已过期");
            }
            // 4. 防重放攻击校验
            String nonceKey = "api:nonce:" + nonce;
            Boolean setResult = redisTemplate.opsForValue().setIfAbsent(nonceKey, "1", 5, TimeUnit.MINUTES);
            if (!setResult) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "重复请求");
            }
            // 5. 用户认证
            log.info("开始用户认证，accessKey: {}", accessKey);
            User user = userService.getByAccessKey(accessKey);
            if (user == null) {
                log.error("用户不存在，accessKey: {}", accessKey);
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "用户不存在");
            }
            log.info("用户认证成功，用户: {}", user.getUserAccount());
            // 6. 签名校验
            // 添加调试信息
            String serverSign = SignUtils.genSign(body, user.getSecretKey());
            log.info("签名验证 - 客户端签名: {}, 服务端签名: {}, body: {}, secretKey: {}",
                    sign, serverSign, body, user.getSecretKey());
            if (!sign.equals(serverSign)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "签名错误");
            }
            // 7. 设置用户信息到请求上下文
            request.setAttribute("user", user);
            // 8. 记录调用日志
            log.info("API调用 - 接口: {}, 用户: {}, 时间: {}", 
                    apiAuthCheck.interfaceName(), user.getUserAccount(), System.currentTimeMillis());
            // 9. 执行原方法
            Object result = joinPoint.proceed();
            return result;
            
        } catch (BusinessException e) {
            log.error("API认证失败 - 接口: {}, 错误: {}", apiAuthCheck.interfaceName(), e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("API认证异常 - 接口: {}, 异常: {}", apiAuthCheck.interfaceName(), e.getMessage());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "系统异常");
        }
    }
    
    /**
     * 获取当前请求
     */
    private HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes != null ? attributes.getRequest() : null;
    }


}